/******************************************************************************* * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ant.internal.ui.preferences; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.ant.core.IAntClasspathEntry; import org.eclipse.ant.internal.core.IAntCoreConstants; import org.eclipse.ant.internal.ui.AntUIPlugin; import org.eclipse.ant.internal.ui.IAntUIConstants; import org.eclipse.ant.internal.ui.IAntUIPreferenceConstants; import org.eclipse.ant.internal.ui.launchConfigurations.VariableInputDialog; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.jdt.ui.wizards.BuildPathDialogAccess; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Tree; public class AntClasspathBlock { private static final String[] TOOLS = new String[] { "tools.jar" }; //$NON-NLS-1$ private TreeViewer treeViewer; private AntClasspathContentProvider antContentProvider; private Button upButton; private Button downButton; private Button removeButton; private AntClasspathLabelProvider labelProvider = new AntClasspathLabelProvider(this); private Button addFolderButton; private Button addJARButton; private Button addExternalJARButton; private Button addVariableButton; private Button antHomeButton; private String antHome; private IDialogSettings dialogSettings = AntUIPlugin.getDefault().getDialogSettings(); private IAntBlockContainer container; private int validated = 2; private IClasspathEntry currentParent; private SelectionListener selectionListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Object source = e.getSource(); if (source == addJARButton) { addJars(); } else if (source == addExternalJARButton) { addExternalJars(); } else if (source == addFolderButton) { addFolder(); } else if (upButton == source) { handleMoveUp(); } else if (downButton == source) { handleMoveDown(); } else if (removeButton == source) { remove(); } else if (addVariableButton == source) { addVariable(); } else if (antHomeButton == source) { browseAntHome(); } } }; public void setContainer(IAntBlockContainer container) { this.container = container; } private void addButtonsToButtonGroup(Composite parent) { addJARButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_addJarButtonTitle); addJARButton.addSelectionListener(selectionListener); addExternalJARButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_42); addExternalJARButton.addSelectionListener(selectionListener); addFolderButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_addFolderButtonTitle); addFolderButton.addSelectionListener(selectionListener); addVariableButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_2); addVariableButton.addSelectionListener(selectionListener); antHomeButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_30); antHomeButton.addSelectionListener(selectionListener); removeButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_removeButtonTitle); removeButton.addSelectionListener(selectionListener); upButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_upButtonTitle); upButton.addSelectionListener(selectionListener); downButton = container.createPushButton(parent, AntPreferencesMessages.AntClasspathBlock_downButtonTitle); downButton.addSelectionListener(selectionListener); } /** * Returns the selected items in the list, in the order they are displayed. * * @return targets for an action */ private List<IAntClasspathEntry> getOrderedSelection(IClasspathEntry parent) { List<IAntClasspathEntry> targets = new ArrayList<>(); List<?> selection = ((IStructuredSelection) treeViewer.getSelection()).toList(); IAntClasspathEntry[] entries = parent.getEntries(); for (int i = 0; i < entries.length; i++) { IAntClasspathEntry target = entries[i]; if (selection.contains(target)) { targets.add(target); } } return targets; } private void handleMoveDown() { List<IAntClasspathEntry> targets = getOrderedSelection(currentParent); List<IAntClasspathEntry> list = new ArrayList<>(Arrays.asList(currentParent.getEntries())); int bottom = list.size() - 1; int index = 0; for (int i = targets.size() - 1; i >= 0; i--) { IAntClasspathEntry target = targets.get(i); index = list.indexOf(target); if (index < bottom) { bottom = index + 1; IAntClasspathEntry temp = list.get(bottom); list.set(bottom, target); list.set(index, temp); } bottom = index; } finishMove(list); } private void finishMove(List<IAntClasspathEntry> list) { AntClasspathContentProvider viewerContentProvider = (AntClasspathContentProvider) treeViewer.getContentProvider(); viewerContentProvider.setEntries(currentParent, list); treeViewer.refresh(); treeViewer.setSelection(treeViewer.getSelection()); updateContainer(); } private void handleMoveUp() { List<IAntClasspathEntry> targets = getOrderedSelection(currentParent); int top = 0; int index = 0; List<IAntClasspathEntry> list = new ArrayList<>(Arrays.asList(currentParent.getEntries())); Iterator<IAntClasspathEntry> entries = targets.iterator(); while (entries.hasNext()) { IAntClasspathEntry target = entries.next(); index = list.indexOf(target); if (index > top) { top = index - 1; IAntClasspathEntry temp = list.get(top); list.set(top, target); list.set(index, temp); } top = index; } finishMove(list); } private void remove() { AntClasspathContentProvider viewerContentProvider = (AntClasspathContentProvider) treeViewer.getContentProvider(); IStructuredSelection sel = (IStructuredSelection) treeViewer.getSelection(); viewerContentProvider.remove(sel); updateContainer(); } /** * Allows the user to enter a folder as a classpath. */ private void addFolder() { String lastUsedPath = dialogSettings.get(IAntUIConstants.DIALOGSTORE_LASTFOLDER); if (lastUsedPath == null) { lastUsedPath = ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString(); } DirectoryDialog dialog = new DirectoryDialog(treeViewer.getControl().getShell()); dialog.setMessage(AntPreferencesMessages.AntClasspathBlock_1); dialog.setFilterPath(lastUsedPath); String result = dialog.open(); if (result != null) { try { URL url = new URL(IAntCoreConstants.FILE_PROTOCOL + result + "/"); //$NON-NLS-1$; ((AntClasspathContentProvider) treeViewer.getContentProvider()).add(currentParent, url); } catch (MalformedURLException e) { // do nothing } } treeViewer.setSelection(treeViewer.getSelection()); dialogSettings.put(IAntUIConstants.DIALOGSTORE_LASTFOLDER, result); updateContainer(); } private void addExternalJars() { String lastUsedPath = dialogSettings.get(IAntUIConstants.DIALOGSTORE_LASTEXTJAR); if (lastUsedPath == null) { lastUsedPath = ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString(); } FileDialog dialog = new FileDialog(treeViewer.getControl().getShell(), SWT.MULTI); dialog.setFilterExtensions(new String[] { "*.jar;*.zip" }); //$NON-NLS-1$ dialog.setFilterPath(lastUsedPath); String result = dialog.open(); if (result == null) { return; } IPath filterPath = new Path(dialog.getFilterPath()); String[] results = dialog.getFileNames(); AntClasspathContentProvider contentProvider = (AntClasspathContentProvider) treeViewer.getContentProvider(); contentProvider.setRefreshEnabled(false); for (int i = 0; i < results.length; i++) { String jarName = results[i]; try { IPath path = filterPath.append(jarName).makeAbsolute(); URL url = new URL(IAntCoreConstants.FILE_PROTOCOL + path.toOSString()); contentProvider.add(currentParent, url); } catch (MalformedURLException e) { // do nothing } } contentProvider.setRefreshEnabled(true); treeViewer.setSelection(treeViewer.getSelection()); dialogSettings.put(IAntUIConstants.DIALOGSTORE_LASTEXTJAR, filterPath.toOSString()); updateContainer(); } private void addJars() { List<IAntClasspathEntry> allEntries = new ArrayList<>(); if (currentParent != null) { allEntries.addAll(Arrays.asList(currentParent.getEntries())); } else { IAntClasspathEntry[] entries = antContentProvider.getModel().getEntries(ClasspathModel.USER); if (entries != null) { allEntries.addAll(Arrays.asList(entries)); } } List<IPath> selectedPaths = new ArrayList<>(allEntries.size()); Iterator<IAntClasspathEntry> iterator = allEntries.iterator(); while (iterator.hasNext()) { IAntClasspathEntry entry = iterator.next(); URL url = entry.getEntryURL(); if (url != null) { String file = url.getFile(); if (file != null && file.length() > 0) { IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(new Path(file).toFile().toURI()); for (int i = 0; i < files.length; i++) { selectedPaths.add(files[i].getFullPath()); } } } } IPath[] paths = BuildPathDialogAccess.chooseJAREntries(treeViewer.getControl().getShell(), null, selectedPaths.toArray(new IPath[selectedPaths.size()])); if (paths != null && paths.length > 0) { AntClasspathContentProvider contentProvider = (AntClasspathContentProvider) treeViewer.getContentProvider(); contentProvider.setRefreshEnabled(false); for (int i = 0; i < paths.length; i++) { String varExpression = VariablesPlugin.getDefault().getStringVariableManager().generateVariableExpression("workspace_loc", paths[i].toString()); //$NON-NLS-1$ contentProvider.add(currentParent, varExpression); } contentProvider.setRefreshEnabled(true); updateContainer(); } } private void updateContainer() { validated = 0; container.update(); } /** * Creates the group which will contain the buttons. */ private void createButtonGroup(Composite top) { Composite buttonGroup = new Composite(top, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; buttonGroup.setLayout(layout); buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL)); buttonGroup.setFont(top.getFont()); addButtonsToButtonGroup(buttonGroup); } private void createClasspathTree(Composite parent) { Tree tree = new Tree(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER); GridData data = new GridData(GridData.FILL_BOTH); data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; data.heightHint = tree.getItemHeight(); tree.setLayoutData(data); tree.setFont(parent.getFont()); tree.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent event) { if (event.character == SWT.DEL && event.stateMask == 0) { remove(); } } }); antContentProvider = new AntClasspathContentProvider(); treeViewer = new TreeViewer(tree); treeViewer.setContentProvider(antContentProvider); treeViewer.setLabelProvider(labelProvider); treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { tableSelectionChanged((IStructuredSelection) event.getSelection(), (AntClasspathContentProvider) treeViewer.getContentProvider()); } }); } public void createContents(Composite parent) { createClasspathTree(parent); createButtonGroup(parent); tableSelectionChanged((IStructuredSelection) treeViewer.getSelection(), antContentProvider); } private void tableSelectionChanged(IStructuredSelection selection, AntClasspathContentProvider contentProvider) { boolean notEmpty = !selection.isEmpty(); boolean first = !notEmpty; boolean last = !notEmpty; boolean canRemove = true; boolean canAdd = notEmpty; boolean canMove = true; if (!resolveCurrentParent(selection)) { // selection contains elements from multiple parents canAdd = false; canMove = false; canRemove = false; } else { Iterator<?> selected = selection.iterator(); while (selected.hasNext()) { IClasspathEntry element = (IClasspathEntry) selected.next(); if (element instanceof GlobalClasspathEntries) { GlobalClasspathEntries global = (GlobalClasspathEntries) element; canRemove = global.canBeRemoved(); canAdd = global.getType() != ClasspathModel.CONTRIBUTED; canMove = false; } IClasspathEntry parent = element.getParent(); if (parent instanceof GlobalClasspathEntries) { canAdd = ((GlobalClasspathEntries) parent).getType() != ClasspathModel.CONTRIBUTED; canRemove = canAdd; canMove = canAdd; } Object[] childEntries = contentProvider.getChildren(parent); List<Object> entries = Arrays.asList(childEntries); int lastEntryIndex = entries.size() - 1; if (!first && entries.indexOf(element) == 0) { first = true; } if (!last && entries.indexOf(element) == lastEntryIndex) { last = true; } } } addJARButton.setEnabled(canAdd); addExternalJARButton.setEnabled(canAdd); addFolderButton.setEnabled(canAdd); addVariableButton.setEnabled(canAdd); removeButton.setEnabled(notEmpty && canRemove); upButton.setEnabled(canMove && !first); downButton.setEnabled(canMove && !last); } private boolean resolveCurrentParent(IStructuredSelection selection) { currentParent = null; Iterator<?> selected = selection.iterator(); while (selected.hasNext()) { Object element = selected.next(); if (element instanceof ClasspathEntry) { IClasspathEntry parent = ((IClasspathEntry) element).getParent(); if (currentParent != null) { if (!currentParent.equals(parent)) { return false; } } else { currentParent = parent; } } else { if (currentParent != null) { if (!currentParent.equals(element)) { return false; } } else { currentParent = (IClasspathEntry) element; } } } return true; } private File validateAntHome(String path) { File rootDir = null; boolean invalid = true; if (path.length() > 0) { rootDir = new File(path, "lib"); //$NON-NLS-1$ File parentDir = rootDir.getParentFile(); if (parentDir == null || !parentDir.exists()) { container.setErrorMessage(AntPreferencesMessages.AntClasspathBlock_56); } else if (!rootDir.exists()) { container.setErrorMessage(AntPreferencesMessages.AntClasspathBlock_7); } else { invalid = false; } } else { container.setErrorMessage(AntPreferencesMessages.AntClasspathBlock_57); } if (invalid) { setValidated(); return null; } container.setErrorMessage(null); return rootDir; } private void browseAntHome() { String lastUsedPath = dialogSettings.get(IAntUIConstants.DIALOGSTORE_LASTANTHOME); if (lastUsedPath == null) { lastUsedPath = ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString(); } DirectoryDialog dialog = new DirectoryDialog(treeViewer.getControl().getShell()); dialog.setMessage(AntPreferencesMessages.AntClasspathBlock_3); dialog.setFilterPath(lastUsedPath); String path = dialog.open(); if (path == null) { return; } antHome = path; if (path.length() > 0) { File rootDir = new File(path, "lib"); //$NON-NLS-1$ setAntHome(rootDir); } else { updateContainer(); } dialogSettings.put(IAntUIConstants.DIALOGSTORE_LASTANTHOME, path); } private void setAntHome(File rootDir) { AntClasspathContentProvider contentProvider = (AntClasspathContentProvider) treeViewer.getContentProvider(); contentProvider.setRefreshEnabled(false); contentProvider.removeAllGlobalAntClasspathEntries(); String[] names = rootDir.list(); if (names != null) { Arrays.sort(names); for (int i = 0; i < names.length; i++) { File file = new File(rootDir, names[i]); if (file.isFile() && file.getPath().endsWith(".jar")) { //$NON-NLS-1$ try { URL url = new URL(IAntCoreConstants.FILE_PROTOCOL + file.getAbsolutePath()); contentProvider.add(ClasspathModel.ANT_HOME, url); } catch (MalformedURLException e) { // do nothing } } } } contentProvider.setRefreshEnabled(true); updateContainer(); } public String getAntHome() { return antHome; } public void initializeAntHome(String antHomeString) { antHome = antHomeString; } public void setInput(ClasspathModel model) { treeViewer.setInput(model); validated = 0; } public boolean validateAntHome() { validated++; return validateAntHome(antHome) != null; } public Image getClasspathImage() { return labelProvider.getClasspathImage(); } public boolean validateToolsJAR() { validated++; boolean check = AntUIPlugin.getDefault().getPreferenceStore().getBoolean(IAntUIPreferenceConstants.ANT_TOOLS_JAR_WARNING); if (check && !AntUIPlugin.isMacOS()) { Object[] entries = antContentProvider.getModel().getEntries(ClasspathModel.ANT_HOME); boolean valid = !JARPresent(entries, TOOLS).isEmpty(); if (!valid) { entries = antContentProvider.getModel().getEntries(ClasspathModel.GLOBAL_USER); valid = !JARPresent(entries, TOOLS).isEmpty(); if (!valid) { entries = antContentProvider.getModel().getEntries(ClasspathModel.USER); valid = !JARPresent(entries, TOOLS).isEmpty(); if (!valid) { MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(AntUIPlugin.getActiveWorkbenchWindow().getShell(), AntPreferencesMessages.AntClasspathBlock_31, AntPreferencesMessages.AntClasspathBlock_32, AntPreferencesMessages.AntClasspathBlock_33, false, AntUIPlugin.getDefault().getPreferenceStore(), IAntUIPreferenceConstants.ANT_TOOLS_JAR_WARNING); valid = dialog.getReturnCode() == IDialogConstants.YES_ID; } } } if (!valid) { container.setErrorMessage(AntPreferencesMessages.AntClasspathBlock_34); setValidated(); } return valid; } return true; } private List<String> JARPresent(Object[] classpathEntries, String[] suffixes) { if (classpathEntries == null) { return Collections.EMPTY_LIST; } List<String> found = new ArrayList<>(2); for (int i = 0; i < classpathEntries.length; i++) { String file; Object entry = classpathEntries[i]; if (entry instanceof URL) { file = ((URL) entry).getFile(); } else { file = entry.toString(); } for (int j = 0; j < suffixes.length; j++) { String suffix = suffixes[j]; if (file.endsWith(suffix)) { found.add(suffix); } } } return found; } public boolean isValidated() { return validated >= 2; } public void setValidated() { validated = 2; } private void addVariable() { VariableInputDialog inputDialog = new VariableInputDialog(treeViewer.getControl().getShell()); inputDialog.open(); String variableString = inputDialog.getVariableString(); if (variableString != null && variableString.trim().length() > 0) { ((AntClasspathContentProvider) treeViewer.getContentProvider()).add(currentParent, variableString); treeViewer.setSelection(treeViewer.getSelection()); updateContainer(); } } }